/******************************************************************************/
/*                                                                            */
/*  Copyright (c) 2007-2009: ngi-central.org                                  */
/*  All rights reserved.                                                      */
/*                                                                            */
/******************************************************************************/


/// \file
/// This file implements data structures for moments calculations.


#ifndef __sgl_flusser_moments_h__
#define __sgl_flusser_moments_h__

#include <sgl/global_settings.h>
#include <sgl/conditions.h>
#include <sgl/scale_invariant_moments.h>
#include <sgl/real_concept.h>
#include <boost/concept_check.hpp>

namespace sgl {


/******************************************************************************/
/*                                                                            */
/* flusser_moments                                                            */
/*                                                                            */
/******************************************************************************/

template <
	/// The type. 
	//! 
	//! This type defaults to SGL_FPTYPE (which in turn defaults to double), but 
	//! any other numeric type is also suitable.
	typename T=SGL_FPTYPE>
/// Class to hold scale invariant moments up to the third order.
//!
//! The Flusser moments are invariant under affine transformations.
//!
//! The following operations are implemented:
//! operator== : comparison for equality, directly implemented.
//! operator != : comparison for inequality, implemented through 
//! boost::equality_comaparable.
class flusser_moments
	: boost::equality_comparable<sgl::flusser_moments<T>, 
		sgl::flusser_moments<T>
	>
{
	// Only real types qualify for type T. If this line triggers an error,
	// type T is not a real type.
	BOOST_CONCEPT_ASSERT((sgl::real_concept<T>));

public:
	/// The value type.
	typedef T value_type;

	/// Default constructor. 
	//!
	//! Zero initializes the moments.
	flusser_moments()
		: fm1_(T())
		, fm2_(T())
		, fm3_(T())
		, fm4_(T())
	{ }

	/// Standard constructor.
	//!
	//! Initializes the moments.
	flusser_moments(
		/// First Flusser moment.
		T fm1, 
		/// Second Flusser moment.
		T fm2,
		/// Third Flusser moment.
		T fm3,
		/// Fourth Flusser moment.
		T fm4)
		: fm1_(fm1)
		, fm2_(fm2)
		, fm3_(fm3)
		, fm4_(fm4)
	{ }

	/// Constructs Flusser moments from scale invariant moments.
	//!
	//! This calculates Flusser moments from scale invariant moments.
	flusser_moments(
		/// The right hand side.
		sgl::central_moments<T> const& r)
		: fm1_(r.calculate_fm1())
		, fm2_(r.calculate_fm2())
		, fm3_(r.calculate_fm3())
		, fm4_(r.calculate_fm4())
	{ }

	/// Constructs a copy.
	flusser_moments(
		/// The right hand side.
		sgl::flusser_moments<T> const& r)
		: fm1_(r.fm1_)
		, fm2_(r.fm2_)
		, fm3_(r.fm3_)
		, fm4_(r.fm4_)
	{ }

	/// Copy assignment
	sgl::flusser_moments<T> & operator =(
		/// The right hand side.
		sgl::flusser_moments<T> rhs)
	{
		swap(rhs);
		return *this;
	}

	/// Exchanges two objects.
	void swap(
		/// The other object.
		sgl::flusser_moments<T> & rhs)
	{
		std::swap(fm1_, rhs.fm1_);
		std::swap(fm2_, rhs.fm2_);
		std::swap(fm3_, rhs.fm3_);
		std::swap(fm4_, rhs.fm4_);
	}

	/// Compare objects for equality.
	//!
	//! This instance is equal to another instance, if its moments are all equal 
	//! to the moments of the other instance.
	//!
	//! Through the use of boost::equality_comparable operator != is also
	//! defined and implemented by calling this operator.
	//!
	//! \return true if equal, false otherwise.
    bool operator ==(
		/// Right hand side.
		sgl::flusser_moments<T> const& rhs) const
    {
        return 
			fm1_ == rhs.fm1_ && 
			fm2_ == rhs.fm2_ &&
			fm3_ == rhs.fm3_ && 
			fm4_ == rhs.fm4_ ;
    }

	/// Access the first Flusser moment.
	//!
	//! /return Returns a reference to the first Flusser moment.
	T & fm1()
	{
		return fm1_;
	}

	/// Access the first Flusser moment.
	//!
	//! /return Returns a const reference to the first Flusser moment.
	T const & fm1() const
	{
		return fm1_;
	}

	/// Access the second Flusser moment.
	//!
	//! /return Returns a reference to the second Flusser moment.
	T & fm2()
	{
		return fm2_;
	}

	/// Access the second Flusser moment.
	//!
	//! /return Returns a const reference to the second Flusser moment.
	T const & fm2() const
	{
		return fm2_;
	}

	/// Access the third Flusser moment.
	//!
	//! /return Returns a reference to the third Flusser moment.
	T & fm3()
	{
		return fm3_;
	}

	/// Access the third Flusser moment.
	//!
	//! /return Returns a constst reference to the third Flusser moment.
	T const & fm3() const
	{
		return fm3_;
	}

	/// Access the fourth Flusser moment.
	//!
	//! /return Returns a reference to the fourth Flusser moment.
	T & fm4()
	{
		return fm4_;
	}

	/// Access the fourth Flusser moment.
	//!
	//! /return Returns a const reference to the fourth Flusser moment.
	T const & fm4() const
	{
		return fm4_;
	}

private:
	/// The first Flusser moment.
	T fm1_;

	/// The second Flusser moment.
	T fm2_;

	/// The third Flusser moment.
	T fm3_;

	/// The fourth Flusser moment.
	T fm4_;
};


} // namespace sgl

#endif // __sgl_flusser_moments_h__
